!pip install pyreadstat
!pip install pandas-profiling==2.7.1
!wget -q "https://github.com/casalazara/Data-Science-Aplicado/blob/master/Lab2/B.sav?raw=true" -O "B.sav"
!wget -q "https://github.com/casalazara/Data-Science-Aplicado/blob/master/Lab2/D.sav?raw=true" -O "D.sav"
!wget -q "https://github.com/casalazara/Data-Science-Aplicado/blob/master/Lab2/H.sav?raw=true" -O "H.sav"
# Importante librerias o modulos que se van a usar en esta sesion
import os, sys
import numpy as np
import pandas as pd
import pandas_profiling
##Librerías para graficar
import matplotlib
matplotlib.style.use('ggplot')
from matplotlib import pyplot as plt
condiVida = pd.read_spss('B.sav')
fuerTrabajo = pd.read_spss('H.sav')
condiVida.head()
fuerTrabajo.head()
condiVida.dtypes
De acuerdo a la descripción de variables en la página, las columnas P4030S1A1 y P4030S4A1 son las únicas variables numéricas discretas, las demás son continuas. Sin embargo, estas columnas cuentan con valores no numéricos que se deben reemplazar por lo que antes de cambiar el tipo hay que decidir qué hacer con ellos.
def cambiara_int(condiVida):
condiVida["P4030S1A1"]=condiVida["P4030S1A1"].astype(int)
condiVida["P4030S4A1"]=condiVida["P4030S4A1"].astype(int)
duplicados = condiVida.duplicated().sum()
print(duplicados)
condiVida[condiVida.duplicated()]
def missing_values_table(df):
mis_val = df.isnull().sum()
mis_val_percent = 100 * df.isnull().sum()/len(df)
mis_val_table = pd.concat([mis_val, mis_val_percent], axis=1)
mis_val_table_ren_columns = mis_val_table.rename(
columns = {0 : 'Missing Values', 1 : '% of Total Values'})
return mis_val_table_ren_columns
missing_values_table(condiVida)
La mayoría de columnas no tienen valores nulos. Sin embargo, las columnas P4030S1A1 y P4030S4A1 cuentan con valores nulos, la columna P4030S4A1 corresponde de acuerdo al diccionario a el número de días por semana que se realiza la recolección de basuras
(condiVida['P4030S4A1'].value_counts()*100/len(condiVida)).plot(kind='bar')
Mientras que la columna P4030S1A1 corresponde al estrato para la tarifa de la energía eléctrica
(condiVida['P4030S1A1'].value_counts()*100/len(condiVida)).plot(kind='bar')
Para la columna P4030S1A1 dada la baja cantidad de filas con este valor nulo y la importancia del estrato socioeconómico para los análisis lo mejor es eliminar estas filas, para la columna P4030S4A1 dada la distribución de valores lo mejor sería reemplazar los valores faltantes con la moda (3.0)
condiVida.dropna(axis=0, subset=['P4030S1A1'],inplace=True)
condiVida['P4030S4A1'] = condiVida['P4030S4A1'].fillna(condiVida['P4030S4A1'].mode()[0])
missing_values_table(condiVida)
cambiara_int(condiVida)
condiVida.head()
Si una variable contiene valores no lógicos lo primero que haría sobre la base de datos sería mirar los datos de las filas con estos valores de manera que se pueda identificar si el error fue intencionado o no, si no lo fue tratar de mirar una forma de corregirlo de acuerdo al valor allí presente, en caso de no poderse dependría de la importancia de la variable para los análisis el desechar la fila o no.
col_interes = 'DIRECTORIO REGION clase P424 P4030S1 P4030S1A1 P4030S5 P4030S3 P4030S4 P4030S4A1 P4030S2 P4020'.split("\t")
condiVida = condiVida[col_interes]
for columna in condiVida.columns:
print(columna,"\n",condiVida[columna].unique())
De acuerdo al diccionario todos los valores son válidos
fuerTrabajo.dtypes
Las columnas SECUENCIA_P, P1150S1, P1099S1, P6500, P1149S1 y P1148S1 de acuerdo a la información de las variables deberían ser discretas, las columnas P6370S1 y P6390S1 deberían ser continuas, las demás columnas están en el tipo que deberían estar. Sin embargo por la presencia de valores nulos en ellas no se puede hacer el cambio sin haberlos removido previamente
def cambiar_int2(fuerTrabajo):
#fuerTrabajo["P6350"]=fuerTrabajo["P6350"].astype(int) #Se remueve más adelante por la cantidad de ausencias
fuerTrabajo["SECUENCIA_P"]=fuerTrabajo["SECUENCIA_P"].astype(int)
fuerTrabajo['P6370S1'] = fuerTrabajo['P6370S1'].astype(float)
fuerTrabajo['P6390S1'] = fuerTrabajo['P6390S1'].astype(float)
fuerTrabajo['P1150S1'] = fuerTrabajo['P6390S1'].astype(float)
fuerTrabajo['P1099S1'] = fuerTrabajo['P6390S1'].astype(float)
fuerTrabajo['P6500'] = fuerTrabajo['P6390S1'].astype(float)
fuerTrabajo['P1149S1'] = fuerTrabajo['P6390S1'].astype(float)
fuerTrabajo['P1148S1'] = fuerTrabajo['P6390S1'].astype(float)
duplicados = fuerTrabajo.duplicated().sum()
print(duplicados)
fuerTrabajo[fuerTrabajo.duplicated()]
faltantes = missing_values_table(fuerTrabajo)
faltantes
Hay una gran cantidad de columnas con más del 80% de valores faltantes por lo que es mejor removerlas y ver con más detalle la importancia de las que siguen presentando valores nulos
a_remover=[]
for columna in fuerTrabajo.columns:
if faltantes.loc[columna,'% of Total Values'] >= 80:
a_remover.append(columna)
fuerTrabajo.drop(axis=1,columns=a_remover,inplace=True)
missing_values_table(fuerTrabajo)
Para las columnas con valores faltantes considero prudente eliminar las filas que no tengan mínimo 14 columnas llenas.
fuerTrabajo.dropna(subset=['P6880','P6440','P6400','P1151','P1150','P1150S1','P1150S2','P1099S1','P1099S2','P427','P6500','P6750','P6760','P6426','P428','P6250'],thresh=14,inplace=True)
missing_values_table(fuerTrabajo)
for columna in (['P6400','P6500','P6750','P6760']):
print(fuerTrabajo[columna].value_counts())
Hay una gran similitud entre los valores de las columnas numéricas salvo P6760, para estas similares sugiero llenar los valores vacíos con la media y para las columnas P6400 y P6760 considero que lo mejor sería llenar los valores nulos con la moda pues hay una gran diferencia respecto a los demás valores.
fuerTrabajo['P6760'] = fuerTrabajo['P6760'].fillna(fuerTrabajo['P6760'].mode()[0])
fuerTrabajo['P6400'] = fuerTrabajo['P6400'].fillna(fuerTrabajo['P6400'].mode()[0])
fuerTrabajo['P6750'] = fuerTrabajo['P6750'].fillna(fuerTrabajo['P6750'].mean())
fuerTrabajo['P6500'] = fuerTrabajo['P6500'].fillna(fuerTrabajo['P6500'].mean())
cambiar_int2(fuerTrabajo)
missing_values_table(fuerTrabajo)
for columna in fuerTrabajo.columns:
print(columna,"\n",fuerTrabajo[columna].unique())
De acuerdo al diccionario los valores son válidos.
compHogar = pd.read_spss('D.sav')
compHogar.head()
compHogar.dtypes
Las columnas SECUENCIA_P, P6040, P1174S1A1, P1174S2A1, P1144S3A1, P576252 y P575452 corresponden a valores discretos por lo que es necesario pasarlos a tipo entero
def cambiar_int3(compHogar):
columnas = ["SECUENCIA_P", "P6040", "P1174S1A1", "P1174S2A1", "P1144S3A1", "P576252", "P575452"]
columnas.remove('P1174S1A1') #Las remuevo pues más adelante se eliminarán
columnas.remove('P1174S2A1')
columnas.remove('P1144S3A1')
columnas.remove('P576252')
columnas.remove('P575452')
for columna in columnas:
compHogar[columna]=compHogar[columna].astype(int)
duplicados = compHogar.duplicated().sum()
print(duplicados)
compHogar[compHogar.duplicated()]
faltantes = missing_values_table(compHogar)
faltantes
Encontramos bastantes columnas con más del 80% de sus valores como nulos por lo que serán las primeras en ser eliminadas pues al verificar en el diccionario se puede evidenciar que salvo las variables P1174 y P1172 son ellas quienes permiten especificar la respuesta a una pregunta previa
a_remover=[]
for columna in compHogar.columns:
if faltantes.loc[columna,'% of Total Values'] >= 80 and columna not in ["P1174","P1172"]:
a_remover.append(columna)
compHogar.drop(axis=1,columns=a_remover,inplace=True)
missing_values_table(compHogar)
Ahora vamos a dejar las filas que tengan 13 columnas llenas de las 15
compHogar.dropna(thresh=13,inplace=True)
missing_values_table(compHogar)
for columna in ['P1172','P1172S1','P5762S2','P5754S2','P1174']:
print(compHogar[columna].value_counts())
Para estos valores nulos considero que lo mejor sería completarlos de acuerdo a la probabilidad de ocurrencia de los distintos valores en la columna
cambiar_int3(compHogar)
for columna in ['P1172','P1172S1','P5762S2','P5754S2','P1174']:
s = compHogar[columna].value_counts(normalize=True)
missing = compHogar[columna].isnull()
compHogar.loc[missing,columna] = np.random.choice(s.index, size=len(compHogar[missing]),p=s.values)
missing_values_table(compHogar)
for columna in compHogar.columns:
print(columna,"\n",compHogar[columna].unique())
De acuerdo al diccionario todos los valores son válidos
final = pd.merge(compHogar,fuerTrabajo, how='inner',on='DIRECTORIO')
final = pd.merge(condiVida, final, how='inner',on='DIRECTORIO')
final.head()
pandas_profiling.ProfileReport(final)